package com.ouc.visualization.dao.impl;

import com.ouc.common.constant.ConstantFiled;
import com.ouc.common.utils.MathUtils;
import com.ouc.common.utils.ToPictureUtil;
import com.ouc.visualization.dao.NcPictDaoVisualization;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

import static com.ouc.common.utils.ToPictureUtil.*;


/**
 * 图片相关操作
 *
 * @author B504
 */
@Component
public class NcPictDaoVisualizationImpl implements NcPictDaoVisualization {
  @Override
  public BufferedImage getPictFromNcData2D(float[][] data, Float fixedMin, Float fixedMax, String colorType) throws IOException {
    float[][] floats;
    if (fixedMax != null && fixedMin != null) {
      floats = MathUtils.normalizeByLinear(data, fixedMin, fixedMax, false);
    } else {
      floats = MathUtils.normalizeByLinear(data);
    }
    Integer[][] integers = new Integer[floats.length][floats[0].length];
    for (int i = 0; i < floats.length; i++) {
      for (int j = 0; j < floats[i].length; j++) {
        if (Float.isNaN(floats[i][j])) {
          integers[i][j] = null;
          continue;
        }
        integers[i][j] = (int) (floats[i][j] * 512);
      }
    }

    return ToPictureUtil.toImageFromData(integers, colorType);
  }

  @Override
  public BufferedImage getPictFromNcData2DByLine(Integer[][] data, String colorType) throws IOException, ExecutionException, InterruptedException {
    Map<Integer, int[]> colorMap = ToPictureUtil.getRainbow();
    switch (colorType) {
      case "cooltowarm":
        colorMap = getCooltowarm();
        break;
      case "blackbody":
        colorMap = getBlackbody();
        break;
      case "grayscale":
        colorMap = getGrayscale();
        break;
      default:
        break;
    }
    BufferedImage bufImg = new BufferedImage(data.length, data[0].length, BufferedImage.TYPE_INT_ARGB);
    //设置画笔
    Graphics2D graphics = bufImg.createGraphics();
    // 设置线程池
    ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();
    setTempThreadPoolTaskExecutor(executorService);
    CompletableFuture<BufferedImage>[] task = new CompletableFuture[data.length];
    for (int i = 0; i < data.length; i++) {
      final int idx = i;
      Map<Integer, int[]> finalColorMap = colorMap;
      task[i] = CompletableFuture.supplyAsync(() -> {
        try {
          return getBuffImageByLine(data[idx], finalColorMap);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      }, executorService);
    }


    // 将每个线程返回的BufferedImage对象合并成一个完整的图像
    for (int i = 0; i < task.length; i++) {
      BufferedImage subImg = task[i].get();
      graphics.drawImage(subImg, i, 0, null);
    }
    // 等待所有线程执行完成
    executorService.shutdown();
    // 防止线程无法正常关闭
    executorService.setAwaitTerminationMillis(Long.MAX_VALUE);
    // 输出图片
    // 进行图片旋转，旋转-90度
    return rotateImage(bufImg, -90);
  }

  private BufferedImage getBuffImageByLine(Integer[] data, Map<Integer, int[]> finalColorMap) {
    BufferedImage subImg = new BufferedImage(1, data.length, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g2 = subImg.createGraphics();
    for (int j = 0; j < data.length; j++) {
      if (data[j] == null) {
        g2.setColor(Color.LIGHT_GRAY);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0));
      } else {
        // 设置颜色RGB数组
        int[] ints = getColorFromData(finalColorMap, data[j]);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
        g2.setColor(new Color(ints[0], ints[1], ints[2]));
      }
      g2.fillRect(0, j, 1, 1);
    }
    return subImg;
  }

  private ThreadPoolTaskExecutor setTempThreadPoolTaskExecutor(ThreadPoolTaskExecutor threadPoolTaskExecutor) {
    int core = Runtime.getRuntime().availableProcessors() + 1;

    //配置核心线程数

    threadPoolTaskExecutor.setCorePoolSize(core);

    //配置最大线程数

    threadPoolTaskExecutor.setMaxPoolSize(core * 2);

    //配置队列大小

    threadPoolTaskExecutor.setQueueCapacity(1000);

    //线程池维护线程所允许的空闲时间

    threadPoolTaskExecutor.setKeepAliveSeconds(120);

    //配置线程池中的线程的名称前缀

    threadPoolTaskExecutor.setThreadNamePrefix(ConstantFiled.KMALL_THREAD_NAME_PREFIX);

    //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean

    threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);

    //设置线程池中任务的等待时间，如果超过这个时候还没有销毁就强制销毁，以确保应用最后能够被关闭，而不是阻塞住

    threadPoolTaskExecutor.setAwaitTerminationSeconds(60);

    // rejection-policy：当pool已经达到max size的时候，如何处理新任务

    // CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行

    threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

    //执行初始化

    threadPoolTaskExecutor.initialize();

    return threadPoolTaskExecutor;
  }

  @Override
  public BufferedImage getPictFromNcData2D(float[][] data, String colorType) throws IOException {

    return getPictFromNcData2D(data, null, null, colorType);
  }

  @Override
  public Integer[][] getColorIndexData(float[][] data, Float fixedMin, Float fixedMax) {
    float[][] floats;

    if (fixedMax != null && fixedMin != null) {
      floats = MathUtils.normalizeByLinear(data, fixedMin, fixedMax, false);
    } else {
      floats = MathUtils.normalizeByLinear(data);
    }
    Integer[][] integers = new Integer[floats.length][floats[0].length];
    for (int i = 0; i < floats.length; i++) {
      for (int j = 0; j < floats[i].length; j++) {
        if (Float.isNaN(floats[i][j])) {
          integers[i][j] = null;
          continue;
        }
        integers[i][j] = (int) (floats[i][j] * 512);
      }
    }
    return integers;
  }

  @Override
  public Integer[][] getColorIndexData(float[][] data) {
    return getColorIndexData(data, null, null);
  }
}
